package com.ljx.itbbs.server.user.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.ljx.itbbs.common.constant.CacheConstants;
import com.ljx.itbbs.common.domain.model.LoginUser;
import com.ljx.itbbs.common.exception.BusinessException;
import com.ljx.itbbs.common.utils.AssertUtil;
import com.ljx.itbbs.common.utils.RedisUtil;
import com.ljx.itbbs.common.utils.ServletUtil;
import com.ljx.itbbs.security.context.AuthenticationContextHolder;
import com.ljx.itbbs.security.service.TokenService;
import com.ljx.itbbs.server.user.domain.entity.RoleEntity;
import com.ljx.itbbs.server.user.domain.vo.req.RegisterBody;
import com.ljx.itbbs.server.user.domain.vo.resp.UserResp;
import com.ljx.itbbs.server.user.service.AuthService;
import com.ljx.itbbs.server.user.service.RoleService;
import com.ljx.itbbs.server.user.service.UserService;
import com.ljx.itbbs.server.user.service.adapter.UserAdapter;
import com.ljx.itbbs.server.user.service.cache.UserCache;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.stream.Collectors;

/**
 * @Author: LiJunXi
 * @Description:
 * @Date: 2024-03-22  21:44
 */
@Service
public class AuthServiceImpl implements AuthService {

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private TokenService tokenService;

    @Autowired
    private UserService userService;

    @Autowired
    private RoleService roleService;

    @Override
    public String login(String username, String password, String code, String uuid, String checkCodeType) {
        // 检验验证码
        checkCode(uuid, code, checkCodeType);
        // 用户验证
        Authentication authentication = null;
        try {
            // 这里将用户信息保存在本地线程中，用于比较密码是否一致
            UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);
            AuthenticationContextHolder.setContext(authenticationToken);
            // 该方法会去调用UserDetailsServiceImpl.loadUserByUsername
            authentication = authenticationManager.authenticate(authenticationToken);
        }
        catch (Exception e) {
            throw new BusinessException(e.getMessage());
        } finally {
            AuthenticationContextHolder.clearContext();
        }
        LoginUser loginUser = (LoginUser) authentication.getPrincipal();
        // 更新用户上线状态
        return tokenService.createToken(loginUser);
    }


    private void checkCode(String uuid, String code, String checkCodeType) {
        String key = CacheConstants.getKey(CacheConstants.LOGIN_CODE, checkCodeType + "_" + uuid);
        String ans = RedisUtil.get(key);
        AssertUtil.isNotEmpty(ans, "验证码已过期");
        AssertUtil.equal(ans, code, "验证码错误");
        // 清除验证码缓存
        RedisUtil.del(key);
    }

    @Override
    public void registerBody(RegisterBody registerBody) {
        // 检验密码
        AssertUtil.equal(registerBody.getPasswordAgain(), registerBody.getPassword(), "两次密码不一致");
        // 检验验证码
        checkCode(registerBody.getUuid(), registerBody.getCode(), registerBody.getCheckCodeType());
        // 检验是否存在
        AssertUtil.isTrue(userService.checkUsernameUnique(registerBody.getUsername()), "注册账号已存在");
        // 保存账号
        userService.registerUser(registerBody.getUsername(), registerBody.getPassword());

    }

    @Override
    public UserResp getUserInfo() {
        Long userId = ServletUtil.getUserId();
        List<String> roleList = roleService.getByUId(userId)
                .stream().map(RoleEntity::getName).collect(Collectors.toList());

        return UserAdapter.buildAuthUserResp(userService.getUserInfoById(userId), roleList);
    }
}
